package com.sds.ai.impl.provider;

import com.google.common.base.Function;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.sds.ai.api.provider.DataProvider;
import com.sds.ai.impl.data.HasKey;
import org.apache.log4j.Logger;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
import java.util.List;


@Singleton
public class DataProviderImpl implements DataProvider {

    private final Logger LOGGER = Logger.getLogger(getClass());

    private final EntityManagerFactory EMF;

    @Inject
    public DataProviderImpl(EntityManagerFactory EMF) {
        this.EMF = EMF;
        LOGGER.info("Data provider created");
    }

    public <T extends HasKey> T getManagedInstance(T object) {
        EntityManager entityManager = EMF.createEntityManager();
        try {
            if (object.getKey() == null) {
                entityManager.persist(object);
                entityManager.clear();
            }
            return (T) entityManager.find(object.getClass(), object.getKey());
        } finally {
            entityManager.close();
        }
    }

    public <T extends HasKey> T update(T object) {
        EntityManager entityManager = EMF.createEntityManager();
        try {
            return entityManager.merge(object);
        } finally {
            entityManager.close();
        }
    }

    public <T extends HasKey> List<T> getAll(Class<T> clazz) {
        EntityManager entityManager = EMF.createEntityManager();
        try {
            Query query = entityManager.createQuery("select from " + clazz.getName());
            List list = query.getResultList();
            return Lists.newArrayList(Iterators.transform(
                    list.iterator(),
                    new Function<Object, T>() {
                        @Override
                        public T apply(Object input) {
                            return (T) input;
                        }
                    }
            ));
        } finally {
            entityManager.close();
        }
    }
}
